This notebook examines the relationship between different features of the data for distinguishing viral from nonviral sequences.

Please reach out to James Riddell () or Bridget Hegarty () regarding any issues, or open an issue on github.

library(ggplot2)
library(plyr)
library(reshape2)
library(viridis)
Loading required package: viridisLite
library(tidyr)

Attaching package: ‘tidyr’

The following object is masked from ‘package:reshape2’:

    smiths
library(dplyr)

Attaching package: ‘dplyr’

The following objects are masked from ‘package:plyr’:

    arrange, count, desc, failwith, id, mutate, rename, summarise, summarize

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union
library(readr)
library(data.table)
data.table 1.14.0 using 1 threads (see ?getDTthreads).  Latest news: r-datatable.com
**********
This installation of data.table has not detected OpenMP support. It should still work but in single-threaded mode.
This is a Mac. Please read https://mac.r-project.org/openmp/. Please engage with Apple and ask them for support. Check r-datatable.com for updates, and our Mac instructions here: https://github.com/Rdatatable/data.table/wiki/Installation. After several years of many reports of installation problems on Mac, it's time to gingerly point out that there have been no similar problems on Windows or Linux.
**********

Attaching package: ‘data.table’

The following objects are masked from ‘package:dplyr’:

    between, first, last

The following objects are masked from ‘package:reshape2’:

    dcast, melt
viruses <- read_tsv("../IntermediaryFiles/viral_tools_combined.tsv")

── Column specification ──────────────────────────────────────────────────────────────────────────────────────────────────────────
cols(
  .default = col_double(),
  seqtype = col_character(),
  contig = col_character(),
  checkv_provirus = col_character(),
  checkv_quality = col_character(),
  method.x = col_character(),
  Classified = col_character(),
  IDs_all = col_character(),
  Seq = col_character(),
  Kaiju_Viral = col_character(),
  Kingdom = col_character(),
  type = col_character(),
  vibrant_quality = col_character(),
  method.y = col_character(),
  vibrant_prophage = col_character(),
  vs2type = col_character(),
  max_score_group = col_character()
)
ℹ Use `spec()` for the full column specifications.
colnames(viruses)
 [1] "Index"                "seqtype"              "contig"               "checkv_provirus"      "checkv_completeness"  "checkv_contamination"
 [7] "checkv_viral_genes"   "checkv_host_genes"    "checkv_total_genes"   "checkv_length"        "checkv_quality"       "method.x"            
[13] "Classified"           "NCBI_taxon"           "len"                  "ID_best"              "IDs_all"              "Seq"                 
[19] "Kaiju_Viral"          "Kingdom"              "score"                "pvalue"               "bh_pvalue"            "type"                
[25] "vibrant_quality"      "method.y"             "vibrant_prophage"     "category"             "vs2type"              "dsDNAphage"          
[31] "ssDNA"                "NCLDV"                "RNA"                  "lavidaviridae"        "max_score"            "max_score_group"     
[37] "hallmark"             "viral"                "cellular"             "percent_host"         "percent_viral"        "percent_unknown"     
There were 25 warnings (use warnings() to see them)
plot(viruses$RNA, viruses$viral)
There were 50 or more warnings (use warnings() to see the first 50)

plot(viruses$lavidaviridae, viruses$viral)

plot(viruses$NCLDV, viruses$viral)

plot(viruses$ssDNA, viruses$viral)

plot(viruses$checkv_completeness, viruses$hallmark)

Important features by sequence type

pal <- ggthemes::tableau_color_pal(palette="Tableau 10", type="regular")

ggplot(viruses, aes(x=checkv_host_genes, y=checkv_viral_genes)) +
There were 34 warnings (use warnings() to see them)
  geom_hex(bins = 30) +
  scale_fill_continuous(type = "viridis", trans="log10") +
  theme_bw() +
  facet_wrap(~seqtype, scales = "free") +
  xlab("Number of Host Genes") +
  ylab("Number of Viral Genes")

ggplot(viruses, aes(x=hallmark, y=checkv_length)) +
There were 32 warnings (use warnings() to see them)
  geom_hex(bins = 30) +
  scale_fill_continuous(type = "viridis", trans="log10") +
  theme_bw() +
  facet_wrap(~seqtype, scales = "free") +
  xlab("Number of Hallmark Genes") +
  ylab("Length of Sequence") 

ggplot(viruses, aes(x=checkv_length, y=checkv_completeness)) +
  geom_hex(bins = 30) +
  scale_fill_continuous(type = "viridis", trans="log10") +
  theme_bw() +
  facet_wrap(~seqtype, scales = "free") +
  xlab("Length") +
  ylab("Completeness") 

ggplot(viruses, aes(x=hallmark, y=checkv_completeness)) +
There were 30 warnings (use warnings() to see them)
  geom_hex(bins = 30) +
  scale_fill_continuous(type = "viridis", trans="log10") +
  theme_bw() +
  facet_wrap(~seqtype, scales = "free") +
  xlab("Hallmark Genes") +
  ylab("Completeness") 

table(viruses$seqtype[viruses$checkv_length>50000 & viruses$hallmark==0])/table(viruses$seqtype)

  archaea  bacteria     fungi   plasmid   protist     virus 
0.3314556 0.2962900 0.5605600 0.4841683 0.0168000 0.0184000 
table(viruses$seqtype[((viruses$checkv_viral_genes*3) <= viruses$checkv_host_genes) & viruses$checkv_provirus=="No"])/table(viruses$seqtype)

  archaea  bacteria     fungi   plasmid   protist     virus 
0.9842068 0.8948808 0.9263542 0.8298597 0.7198000 0.0210000 
table(viruses$seqtype[viruses$checkv_viral_genes==0 & viruses$checkv_host_genes>=1])/table(viruses$seqtype)

  archaea  bacteria     fungi   plasmid   protist     virus 
0.8565537 0.6711065 0.2422398 0.4166333 0.0306000 0.0057000 
table(viruses$seqtype[viruses$percent_viral>=50])/table(viruses$seqtype)

    archaea    bacteria       fungi     plasmid     protist       virus 
0.000201187 0.027797951 0.006695070 0.004208417 0.053200000 0.306600000 
table(viruses$seqtype[viruses$percent_unknown>=75])/table(viruses$seqtype)

   archaea   bacteria      fungi    plasmid    protist      virus 
0.11628609 0.08322388 0.82349361 0.45511022 0.85360000 0.39280000 
table(viruses$seqtype[viruses$percent_unknown>=75 & viruses$checkv_length<50000])/table(viruses$seqtype)

   archaea   bacteria      fungi    plasmid    protist      virus 
0.10552258 0.08021076 0.34814364 0.25430862 0.83540000 0.25300000 
table(viruses$seqtype[viruses$hallmark>2])/table(viruses$seqtype[viruses$seqtype %in% unique(viruses$seqtype[viruses$hallmark>2])])

    archaea    bacteria     plasmid       virus 
0.008952822 0.045428558 0.055711423 0.576000000 
table(viruses$seqtype, viruses$Kaiju_Viral)
seqdata <- data.frame(seqtype=viruses$seqtype[!duplicated(viruses$contig)])

rownames(seqdata) <- viruses$contig[!duplicated(viruses$contig)]
library(phyloseq)
features_table <- viruses[viruses$Index==1,]
features_table <- features_table[,colnames(features_table) %in% c( 
                                              "checkv_viral_genes",
                                              "checkv_host_genes",
                                              "checkv_unknown_genes",
                                              "checkv_length",
                                              "checkv_completeness",
                                              "checkv_total_genes",
                                              "percent_host",
                                              "percent_viral",
                                              "hallmark",
                                              "percent_unknown"
                                              )]

features_table[is.na(features_table)] <- 0
ft_colnames <- colnames(features_table)
features_table <- t(features_table)
rownames(features_table) <- ft_colnames
colnames(features_table) <- rownames(seqdata)

physeq_pooled <- phyloseq(otu_table(features_table, taxa_are_rows = T))
ordination <- phyloseq::ordinate(physeq =physeq_pooled, method = "PCoA", distance = "bray")
phyloseq::plot_ordination(physeq = physeq_pooled, ordination = ordination,
                          shape="numtools", color="num_viruses") + 
  geom_point(size = 3) +
  theme_bw() +
  geom_label(label=seqdata$toolcombo)

phyloseq::plot_ordination(physeq = physeq_pooled, ordination = ordination,
                          shape="numtools", color="num_viruses") + 
  geom_point(size = 3) +
  theme_bw()

use of each tuning rule

keep_score <- rep(0, nrow(viruses))
There were 44 warnings (use warnings() to see them)
keep_score[viruses$hallmark>2] <- keep_score[viruses$hallmark>2] + 1
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
         0    9852    61777  1643    4712    5000  4240
         1      89     2940     0     278       0  5760
keep_score[viruses$checkv_host_genes>50 & viruses$checkv_provirus=="No"] <- keep_score[viruses$checkv_host_genes>50 & viruses$checkv_provirus=="No"] - 1
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
        -1    2290    14794   492     949       7     0
        0     7580    47164  1151    3776    4993  4240
        1       71     2759     0     265       0  5760
keep_score[viruses$percent_unknown>=75 & viruses$checkv_length<50000] <- keep_score[viruses$percent_unknown>=75 & viruses$checkv_length<50000] + 0.5
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
       -1     2290    14794   492     949       7     0
       0      6535    41993   579    2526     816  2868
       0.5    1045     5171   572    1250    4177  1372
       1        67     2739     0     246       0  4602
       1.5       4       20     0      19       0  1158
keep_score[viruses$percent_viral>=50] <- keep_score[viruses$percent_viral>=50] + 0.5
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
       -1     2290    14794   492     949       7     0
       0      6533    41078   568    2525     550  1220
       0.5    1047     6086   583    1251    4443  3020
       1        67     1855     0     226       0  3184
       1.5       4      904     0      39       0  2576
    #keep_score[viruses$hallmark>=(viruses$checkv_viral_genes/5)] <- keep_score[viruses$hallmark>=(viruses$checkv_viral_genes/5)] + 1 #add some ratio
keep_score[viruses$checkv_viral_genes==0 & viruses$checkv_host_genes>=1] <- keep_score[viruses$checkv_viral_genes==0 & viruses$checkv_host_genes>=1] - 1
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
      -2      1654     6446    14     357       0     0
      -1      6922    43146   724    1609     121    15
      -0.5     574     2186   138     705      39    41
      0        248     6281   322    1508     436  1205
      0.5      473     3901   445     546    4404  2980
      1         66     1854     0     226       0  3184
      1.5        4      903     0      39       0  2575
keep_score[((viruses$checkv_viral_genes*3) <= viruses$checkv_host_genes) & viruses$checkv_provirus=="No"] <- keep_score[((viruses$checkv_viral_genes*3) <= viruses$checkv_host_genes) & viruses$checkv_provirus=="No"] - 1 # consider accounting for provirus designation
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
      -3      1654     6446    14     357       0     0
      -2      6922    43146   723    1603     121    15
      -1.5     574     2186   138     705      39    41
      -1       192     3786   256    1116      54    23
      -0.5     442     2341   392     360    3385   131
      0         56     2504    67     404     382  1182
      0.5       31     1560    53     186    1019  2849
      1         66     1845     0     220       0  3184
      1.5        4      903     0      39       0  2575
#    keep_score[(viruses$checkv_viral_genes*3) <= viruses$checkv_host_genes] <- 0 # consider accounting for provirus designation
keep_score[viruses$checkv_length>500000 & viruses$hallmark==0] <- keep_score[viruses$checkv_length>500000 & viruses$hallmark==0] - 1
table(keep_score, viruses$seqtype)
          
keep_score archaea bacteria fungi plasmid protist virus
      -4       146      129     4      63       0     0
      -3      1841     7482   448     411       5     0
      -2      6589    41981   305    1486     135    15
      -1.5     574     2186   138     705      39    41
      -1       192     3839   247    1120      35    24
      -0.5     442     2341   392     360    3385   131
      0         56     2451    56     400     382  1181
      0.5       31     1560    53     186    1019  2849
      1         66     1845     0     220       0  3184
      1.5        4      903     0      39       0  2575
LS0tCnRpdGxlOiAiVGVzdGluZyBTZXQgRmVhdHVyZXMgVmlzdWFsaXphdGlvbiIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBub3RlYm9vayBleGFtaW5lcyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGlmZmVyZW50IGZlYXR1cmVzIG9mIHRoZSBkYXRhIGZvciBkaXN0aW5ndWlzaGluZyB2aXJhbCBmcm9tIG5vbnZpcmFsIHNlcXVlbmNlcy4KClBsZWFzZSByZWFjaCBvdXQgdG8gSmFtZXMgUmlkZGVsbCAocmlkZGVsbC4yNkBidWNrZXllbWFpbC5vc3UuZWR1KSBvcgpCcmlkZ2V0IEhlZ2FydHkgKGJlaDUzQGNhc2UuZWR1KSByZWdhcmRpbmcgYW55IGlzc3Vlcywgb3Igb3BlbiBhbiBpc3N1ZSBvbiBnaXRodWIuCgpgYGB7ciBzZXR1cC1saWJyYXJ5fQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkocGx5cikKbGlicmFyeShyZXNoYXBlMikKbGlicmFyeSh2aXJpZGlzKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHJlYWRyKQpsaWJyYXJ5KGRhdGEudGFibGUpCmBgYAoKYGBge3J9CnZpcnVzZXMgPC0gcmVhZF90c3YoIi4uL0ludGVybWVkaWFyeUZpbGVzL3ZpcmFsX3Rvb2xzX2NvbWJpbmVkLnRzdiIpCmBgYAoKYGBge3J9CmNvbG5hbWVzKHZpcnVzZXMpCmBgYAoKYGBge3J9CnBsb3QodmlydXNlcyRSTkEsIHZpcnVzZXMkdmlyYWwpCnBsb3QodmlydXNlcyRsYXZpZGF2aXJpZGFlLCB2aXJ1c2VzJHZpcmFsKQpwbG90KHZpcnVzZXMkTkNMRFYsIHZpcnVzZXMkdmlyYWwpCnBsb3QodmlydXNlcyRzc0ROQSwgdmlydXNlcyR2aXJhbCkKcGxvdCh2aXJ1c2VzJGNoZWNrdl9jb21wbGV0ZW5lc3MsIHZpcnVzZXMkaGFsbG1hcmspCmBgYAoKCgoKIyBJbXBvcnRhbnQgZmVhdHVyZXMgYnkgc2VxdWVuY2UgdHlwZQoKYGBge3J9CnBhbCA8LSBnZ3RoZW1lczo6dGFibGVhdV9jb2xvcl9wYWwocGFsZXR0ZT0iVGFibGVhdSAxMCIsIHR5cGU9InJlZ3VsYXIiKQpgYGAKCmBgYHtyfQpnZ3Bsb3QodmlydXNlcywgYWVzKHg9aGFsbG1hcmssIHk9Y2hlY2t2X3ZpcmFsX2dlbmVzKSkgKwogIGdlb21faGV4KGJpbnMgPSAzMCkgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiLCB0cmFucz0ibG9nMTAiKSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+c2VxdHlwZSwgc2NhbGVzID0gImZyZWUiKSArCiAgeGxhYigiTnVtYmVyIG9mIEhhbGxtYXJrIEdlbmVzIikgKwogIHlsYWIoIk51bWJlciBvZiBWaXJhbCBHZW5lcyIpCmBgYAoKYGBge3J9CmdncGxvdCh2aXJ1c2VzLCBhZXMoeD1jaGVja3ZfaG9zdF9nZW5lcywgeT1jaGVja3ZfdmlyYWxfZ2VuZXMpKSArCiAgZ2VvbV9oZXgoYmlucyA9IDMwKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKHR5cGUgPSAidmlyaWRpcyIsIHRyYW5zPSJsb2cxMCIpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5zZXF0eXBlLCBzY2FsZXMgPSAiZnJlZSIpICsKICB4bGFiKCJOdW1iZXIgb2YgSG9zdCBHZW5lcyIpICsKICB5bGFiKCJOdW1iZXIgb2YgVmlyYWwgR2VuZXMiKQpgYGAKCmBgYHtyfQpnZ3Bsb3QodmlydXNlcywgYWVzKHg9cGVyY2VudF91bmtub3duLCB5PXBlcmNlbnRfdmlyYWwpKSArCiAgZ2VvbV9oZXgoYmlucyA9IDMwKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKHR5cGUgPSAidmlyaWRpcyIsIHRyYW5zPSJsb2cxMCIpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5zZXF0eXBlLCBzY2FsZXMgPSAiZnJlZSIpICsKICB4bGFiKCJQZXJjZW50YWdlIG9mIEdlbmVzIFVua25vd24iKSArCiAgeWxhYigiUGVyY2VudGFnZSBvZiBHZW5lcyBWaXJhbCIpCmBgYAoKYGBge3J9CmdncGxvdCh2aXJ1c2VzLCBhZXMoeD1wZXJjZW50X3Vua25vd24sIHk9Y2hlY2t2X2xlbmd0aCkpICsKICBnZW9tX2hleChiaW5zID0gMzApICsKICBzY2FsZV9maWxsX2NvbnRpbnVvdXModHlwZSA9ICJ2aXJpZGlzIiwgdHJhbnM9ImxvZzEwIikgKwogIHRoZW1lX2J3KCkgKwogIGZhY2V0X3dyYXAofnNlcXR5cGUsIHNjYWxlcyA9ICJmcmVlIikgKwogIHhsYWIoIlBlcmNlbnRhZ2Ugb2YgR2VuZXMgVW5rbm93biIpICsKICB5bGFiKCJMZW5ndGggb2YgU2VxdWVuY2UiKQpgYGAKCmBgYHtyfQpnZ3Bsb3QodmlydXNlcywgYWVzKHg9cGVyY2VudF92aXJhbCwgeT1jaGVja3ZfbGVuZ3RoKSkgKwogIGdlb21faGV4KGJpbnMgPSAzMCkgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiLCB0cmFucz0ibG9nMTAiKSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+c2VxdHlwZSwgc2NhbGVzID0gImZyZWUiKSArCiAgeGxhYigiUGVyY2VudGFnZSBvZiBHZW5lcyBWaXJhbCIpICsKICB5bGFiKCJMZW5ndGggb2YgU2VxdWVuY2UiKSAKYGBgCgpgYGB7cn0KZ2dwbG90KHZpcnVzZXMsIGFlcyh4PWhhbGxtYXJrLCB5PWNoZWNrdl9sZW5ndGgpKSArCiAgZ2VvbV9oZXgoYmlucyA9IDMwKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKHR5cGUgPSAidmlyaWRpcyIsIHRyYW5zPSJsb2cxMCIpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5zZXF0eXBlLCBzY2FsZXMgPSAiZnJlZSIpICsKICB4bGFiKCJOdW1iZXIgb2YgSGFsbG1hcmsgR2VuZXMiKSArCiAgeWxhYigiTGVuZ3RoIG9mIFNlcXVlbmNlIikgCmBgYAoKYGBge3J9CmdncGxvdCh2aXJ1c2VzLCBhZXMoeD1jaGVja3ZfbGVuZ3RoLCB5PWNoZWNrdl9jb21wbGV0ZW5lc3MpKSArCiAgZ2VvbV9oZXgoYmlucyA9IDMwKSArCiAgc2NhbGVfZmlsbF9jb250aW51b3VzKHR5cGUgPSAidmlyaWRpcyIsIHRyYW5zPSJsb2cxMCIpICsKICB0aGVtZV9idygpICsKICBmYWNldF93cmFwKH5zZXF0eXBlLCBzY2FsZXMgPSAiZnJlZSIpICsKICB4bGFiKCJMZW5ndGgiKSArCiAgeWxhYigiQ29tcGxldGVuZXNzIikgCmBgYAoKYGBge3J9CmdncGxvdCh2aXJ1c2VzLCBhZXMoeD1oYWxsbWFyaywgeT1jaGVja3ZfY29tcGxldGVuZXNzKSkgKwogIGdlb21faGV4KGJpbnMgPSAzMCkgKwogIHNjYWxlX2ZpbGxfY29udGludW91cyh0eXBlID0gInZpcmlkaXMiLCB0cmFucz0ibG9nMTAiKSArCiAgdGhlbWVfYncoKSArCiAgZmFjZXRfd3JhcCh+c2VxdHlwZSwgc2NhbGVzID0gImZyZWUiKSArCiAgeGxhYigiSGFsbG1hcmsgR2VuZXMiKSArCiAgeWxhYigiQ29tcGxldGVuZXNzIikgCmBgYAoKYGBge3J9CnRhYmxlKHZpcnVzZXMkc2VxdHlwZVt2aXJ1c2VzJGNoZWNrdl9sZW5ndGg+NTAwMDAgJiB2aXJ1c2VzJGhhbGxtYXJrPT0wXSkvdGFibGUodmlydXNlcyRzZXF0eXBlKQp0YWJsZSh2aXJ1c2VzJHNlcXR5cGVbKCh2aXJ1c2VzJGNoZWNrdl92aXJhbF9nZW5lcyozKSA8PSB2aXJ1c2VzJGNoZWNrdl9ob3N0X2dlbmVzKSAmIHZpcnVzZXMkY2hlY2t2X3Byb3ZpcnVzPT0iTm8iXSkvdGFibGUodmlydXNlcyRzZXF0eXBlKQp0YWJsZSh2aXJ1c2VzJHNlcXR5cGVbdmlydXNlcyRjaGVja3ZfdmlyYWxfZ2VuZXM9PTAgJiB2aXJ1c2VzJGNoZWNrdl9ob3N0X2dlbmVzPj0xXSkvdGFibGUodmlydXNlcyRzZXF0eXBlKQoKdGFibGUodmlydXNlcyRzZXF0eXBlW3ZpcnVzZXMkcGVyY2VudF92aXJhbD49NTBdKS90YWJsZSh2aXJ1c2VzJHNlcXR5cGUpCnRhYmxlKHZpcnVzZXMkc2VxdHlwZVt2aXJ1c2VzJHBlcmNlbnRfdW5rbm93bj49NzVdKS90YWJsZSh2aXJ1c2VzJHNlcXR5cGUpCnRhYmxlKHZpcnVzZXMkc2VxdHlwZVt2aXJ1c2VzJHBlcmNlbnRfdW5rbm93bj49NzUgJiB2aXJ1c2VzJGNoZWNrdl9sZW5ndGg8NTAwMDBdKS90YWJsZSh2aXJ1c2VzJHNlcXR5cGUpCnRhYmxlKHZpcnVzZXMkc2VxdHlwZVt2aXJ1c2VzJGhhbGxtYXJrPjJdKS90YWJsZSh2aXJ1c2VzJHNlcXR5cGVbdmlydXNlcyRzZXF0eXBlICVpbiUgdW5pcXVlKHZpcnVzZXMkc2VxdHlwZVt2aXJ1c2VzJGhhbGxtYXJrPjJdKV0pCmBgYAoKYGBge3J9CnRhYmxlKHZpcnVzZXMkc2VxdHlwZSwgdmlydXNlcyRLYWlqdV9WaXJhbCkKYGBgCgpgYGB7cn0Kc2VxZGF0YSA8LSBkYXRhLmZyYW1lKHNlcXR5cGU9dmlydXNlcyRzZXF0eXBlWyFkdXBsaWNhdGVkKHZpcnVzZXMkY29udGlnKV0pCgpyb3duYW1lcyhzZXFkYXRhKSA8LSB2aXJ1c2VzJGNvbnRpZ1shZHVwbGljYXRlZCh2aXJ1c2VzJGNvbnRpZyldCmBgYAoKYGBge3J9CmxpYnJhcnkocGh5bG9zZXEpCmBgYAoKCmBgYHtyfQpmZWF0dXJlc190YWJsZSA8LSB2aXJ1c2VzW3ZpcnVzZXMkSW5kZXg9PTEsXQpmZWF0dXJlc190YWJsZSA8LSBmZWF0dXJlc190YWJsZVssY29sbmFtZXMoZmVhdHVyZXNfdGFibGUpICVpbiUgYyggCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2hlY2t2X3ZpcmFsX2dlbmVzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJjaGVja3ZfaG9zdF9nZW5lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiY2hlY2t2X3Vua25vd25fZ2VuZXMiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZWNrdl9sZW5ndGgiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZWNrdl9jb21wbGV0ZW5lc3MiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgImNoZWNrdl90b3RhbF9nZW5lcyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudF9ob3N0IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJwZXJjZW50X3ZpcmFsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJoYWxsbWFyayIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAicGVyY2VudF91bmtub3duIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKV0KCmZlYXR1cmVzX3RhYmxlW2lzLm5hKGZlYXR1cmVzX3RhYmxlKV0gPC0gMApmdF9jb2xuYW1lcyA8LSBjb2xuYW1lcyhmZWF0dXJlc190YWJsZSkKZmVhdHVyZXNfdGFibGUgPC0gdChmZWF0dXJlc190YWJsZSkKcm93bmFtZXMoZmVhdHVyZXNfdGFibGUpIDwtIGZ0X2NvbG5hbWVzCmNvbG5hbWVzKGZlYXR1cmVzX3RhYmxlKSA8LSByb3duYW1lcyhzZXFkYXRhKQoKcGh5c2VxX3Bvb2xlZCA8LSBwaHlsb3NlcShvdHVfdGFibGUoZmVhdHVyZXNfdGFibGUsIHRheGFfYXJlX3Jvd3MgPSBUKSkKYGBgCgpgYGB7cn0Kb3JkaW5hdGlvbiA8LSBwaHlsb3NlcTo6b3JkaW5hdGUocGh5c2VxID1waHlzZXFfcG9vbGVkLCBtZXRob2QgPSAiUENvQSIsIGRpc3RhbmNlID0gImJyYXkiKQpwaHlsb3NlcTo6cGxvdF9vcmRpbmF0aW9uKHBoeXNlcSA9IHBoeXNlcV9wb29sZWQsIG9yZGluYXRpb24gPSBvcmRpbmF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlPSJudW10b29scyIsIGNvbG9yPSJudW1fdmlydXNlcyIpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHRoZW1lX2J3KCkgKwogIGdlb21fbGFiZWwobGFiZWw9c2VxZGF0YSR0b29sY29tYm8pCgpwaHlsb3NlcTo6cGxvdF9vcmRpbmF0aW9uKHBoeXNlcSA9IHBoeXNlcV9wb29sZWQsIG9yZGluYXRpb24gPSBvcmRpbmF0aW9uLAogICAgICAgICAgICAgICAgICAgICAgICAgIHNoYXBlPSJudW10b29scyIsIGNvbG9yPSJudW1fdmlydXNlcyIpICsgCiAgZ2VvbV9wb2ludChzaXplID0gMykgKwogIHRoZW1lX2J3KCkKYGBgCgp1c2Ugb2YgZWFjaCB0dW5pbmcgcnVsZQpgYGB7cn0Ka2VlcF9zY29yZSA8LSByZXAoMCwgbnJvdyh2aXJ1c2VzKSkKCgprZWVwX3Njb3JlW3ZpcnVzZXMkaGFsbG1hcms+Ml0gPC0ga2VlcF9zY29yZVt2aXJ1c2VzJGhhbGxtYXJrPjJdICsgMQp0YWJsZShrZWVwX3Njb3JlLCB2aXJ1c2VzJHNlcXR5cGUpCmtlZXBfc2NvcmVbdmlydXNlcyRjaGVja3ZfaG9zdF9nZW5lcz41MCAmIHZpcnVzZXMkY2hlY2t2X3Byb3ZpcnVzPT0iTm8iXSA8LSBrZWVwX3Njb3JlW3ZpcnVzZXMkY2hlY2t2X2hvc3RfZ2VuZXM+NTAgJiB2aXJ1c2VzJGNoZWNrdl9wcm92aXJ1cz09Ik5vIl0gLSAxCnRhYmxlKGtlZXBfc2NvcmUsIHZpcnVzZXMkc2VxdHlwZSkKa2VlcF9zY29yZVt2aXJ1c2VzJHBlcmNlbnRfdW5rbm93bj49NzUgJiB2aXJ1c2VzJGNoZWNrdl9sZW5ndGg8NTAwMDBdIDwtIGtlZXBfc2NvcmVbdmlydXNlcyRwZXJjZW50X3Vua25vd24+PTc1ICYgdmlydXNlcyRjaGVja3ZfbGVuZ3RoPDUwMDAwXSArIDAuNQp0YWJsZShrZWVwX3Njb3JlLCB2aXJ1c2VzJHNlcXR5cGUpCmtlZXBfc2NvcmVbdmlydXNlcyRwZXJjZW50X3ZpcmFsPj01MF0gPC0ga2VlcF9zY29yZVt2aXJ1c2VzJHBlcmNlbnRfdmlyYWw+PTUwXSArIDAuNQp0YWJsZShrZWVwX3Njb3JlLCB2aXJ1c2VzJHNlcXR5cGUpCiAgICAja2VlcF9zY29yZVt2aXJ1c2VzJGhhbGxtYXJrPj0odmlydXNlcyRjaGVja3ZfdmlyYWxfZ2VuZXMvNSldIDwtIGtlZXBfc2NvcmVbdmlydXNlcyRoYWxsbWFyaz49KHZpcnVzZXMkY2hlY2t2X3ZpcmFsX2dlbmVzLzUpXSArIDEgI2FkZCBzb21lIHJhdGlvCmtlZXBfc2NvcmVbdmlydXNlcyRjaGVja3ZfdmlyYWxfZ2VuZXM9PTAgJiB2aXJ1c2VzJGNoZWNrdl9ob3N0X2dlbmVzPj0xXSA8LSBrZWVwX3Njb3JlW3ZpcnVzZXMkY2hlY2t2X3ZpcmFsX2dlbmVzPT0wICYgdmlydXNlcyRjaGVja3ZfaG9zdF9nZW5lcz49MV0gLSAxCnRhYmxlKGtlZXBfc2NvcmUsIHZpcnVzZXMkc2VxdHlwZSkKa2VlcF9zY29yZVsoKHZpcnVzZXMkY2hlY2t2X3ZpcmFsX2dlbmVzKjMpIDw9IHZpcnVzZXMkY2hlY2t2X2hvc3RfZ2VuZXMpICYgdmlydXNlcyRjaGVja3ZfcHJvdmlydXM9PSJObyJdIDwtIGtlZXBfc2NvcmVbKCh2aXJ1c2VzJGNoZWNrdl92aXJhbF9nZW5lcyozKSA8PSB2aXJ1c2VzJGNoZWNrdl9ob3N0X2dlbmVzKSAmIHZpcnVzZXMkY2hlY2t2X3Byb3ZpcnVzPT0iTm8iXSAtIDEgIyBjb25zaWRlciBhY2NvdW50aW5nIGZvciBwcm92aXJ1cyBkZXNpZ25hdGlvbgp0YWJsZShrZWVwX3Njb3JlLCB2aXJ1c2VzJHNlcXR5cGUpCiMgICAga2VlcF9zY29yZVsodmlydXNlcyRjaGVja3ZfdmlyYWxfZ2VuZXMqMykgPD0gdmlydXNlcyRjaGVja3ZfaG9zdF9nZW5lc10gPC0gMCAjIGNvbnNpZGVyIGFjY291bnRpbmcgZm9yIHByb3ZpcnVzIGRlc2lnbmF0aW9uCmtlZXBfc2NvcmVbdmlydXNlcyRjaGVja3ZfbGVuZ3RoPjUwMDAwMCAmIHZpcnVzZXMkaGFsbG1hcms9PTBdIDwtIGtlZXBfc2NvcmVbdmlydXNlcyRjaGVja3ZfbGVuZ3RoPjUwMDAwMCAmIHZpcnVzZXMkaGFsbG1hcms9PTBdIC0gMQp0YWJsZShrZWVwX3Njb3JlLCB2aXJ1c2VzJHNlcXR5cGUpCmBgYAoK